import { useEffect, useMemo, useState } from "react";

import { useTeam } from "@/context/team-context";
import { invitationEmailSchema } from "@/ee/features/dataroom-invitations/lib/schema/dataroom-invitations";
import { useUninvitedMembers } from "@/ee/features/dataroom-invitations/lib/swr/use-dataroom-invitations";
import { Link } from "@prisma/client";
import { useSession } from "next-auth/react";
import { toast } from "sonner";
import useSWR from "swr";

import { fetcher } from "@/lib/utils";

import { Button } from "@/components/ui/button";
import {
  Dialog,
  DialogContent,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import { Separator } from "@/components/ui/separator";
import { Textarea } from "@/components/ui/textarea";

type InviteViewersModalProps = {
  open: boolean;
  setOpen: (open: boolean) => void;
  dataroomId: string;
  dataroomName: string;
  groupId?: string;
  linkId?: string;
  defaultEmails?: string[];
  onSuccess?: () => void;
};

type LinkOption = Pick<
  Link,
  "id" | "name" | "domainId" | "domainSlug" | "slug"
>;

function parseRecipientInput(value: string) {
  return Array.from(
    new Set(
      value
        .split(/[\s,]+/)
        .map((email) => email.trim())
        .filter((email) => email.length > 0),
    ),
  );
}

export function InviteViewersModal({
  open,
  setOpen,
  dataroomId,
  dataroomName,
  groupId,
  linkId,
  defaultEmails = [],
  onSuccess,
}: InviteViewersModalProps) {
  const teamInfo = useTeam();
  const teamId = teamInfo?.currentTeam?.id;
  const { data: session } = useSession();
  const senderEmail = session?.user?.email ?? "you";

  const { data: groupLinks } = useSWR<LinkOption[]>(
    groupId && teamId
      ? `/api/teams/${teamId}/datarooms/${dataroomId}/groups/${groupId}/links`
      : null,
    fetcher,
    {
      dedupingInterval: 10000,
    },
  );
  const { uninvitedEmails, mutate: mutateUninvited } = useUninvitedMembers(
    groupId ? dataroomId : undefined,
    groupId,
  );

  const availableLinks: LinkOption[] = useMemo(() => {
    if (groupId) {
      return (
        groupLinks?.map((link) => {
          const last5 = link.id.slice(-5);
          return {
            id: link.id,
            name: link.name || `Link #${last5}`,
            domainId: link.domainId,
            domainSlug: link.domainSlug,
            slug: link.slug,
          };
        }) ?? []
      );
    }

    return linkId
      ? [
          {
            id: linkId,
            name: `Link #${linkId.slice(-5)}`,
            domainId: null,
            domainSlug: null,
            slug: null,
          },
        ]
      : [];
  }, [groupId, groupLinks, linkId]);

  const [selectedLinkId, setSelectedLinkId] = useState<string | undefined>(
    () => linkId ?? availableLinks[0]?.id,
  );
  const [customMessage, setCustomMessage] = useState<string>("");
  const [recipientInput, setRecipientInput] = useState<string>("");
  const [hasEditedRecipients, setHasEditedRecipients] =
    useState<boolean>(false);
  const [loading, setLoading] = useState<boolean>(false);

  useEffect(() => {
    if (!open) {
      setCustomMessage("");
      setRecipientInput("");
      setHasEditedRecipients(false);
      setSelectedLinkId(linkId ?? availableLinks[0]?.id);
      return;
    }

    if (!hasEditedRecipients) {
      const initialRecipients =
        defaultEmails.length > 0
          ? defaultEmails
          : groupId
            ? uninvitedEmails
            : [];

      if (initialRecipients.length > 0) {
        setRecipientInput(initialRecipients.join("\n"));
      }
    }
  }, [
    open,
    linkId,
    availableLinks,
    groupId,
    uninvitedEmails,
    defaultEmails,
    hasEditedRecipients,
  ]);

  useEffect(() => {
    if (!open) {
      setSelectedLinkId(linkId ?? availableLinks[0]?.id);
    }
  }, [open, linkId, availableLinks]);

  const selectedLink = availableLinks.find(
    (link) => link.id === selectedLinkId,
  );

  const defaultRecipients =
    defaultEmails.length > 0 ? defaultEmails : groupId ? uninvitedEmails : [];

  const fallbackSubject = `You are invited to view ${dataroomName}`;

  const handleClose = () => {
    setOpen(false);
    setLoading(false);
  };

  const handleSend = async () => {
    if (!teamId) {
      toast.error("No active team selected");
      return;
    }

    if (groupId && !selectedLinkId) {
      toast.error("Select a link to include in the invitation");
      return;
    }

    const parsedEmails = hasEditedRecipients
      ? parseRecipientInput(recipientInput)
      : [];

    if (parsedEmails.length > 0) {
      const invalidEmails = parsedEmails.filter(
        (email) => !invitationEmailSchema.safeParse(email).success,
      );

      if (invalidEmails.length > 0) {
        toast.error(
          `Found invalid emails: ${invalidEmails
            .slice(0, 3)
            .join(", ")}${invalidEmails.length > 3 ? "..." : ""}`,
        );
        return;
      }
    }

    const endpoint = groupId
      ? `/api/teams/${teamId}/datarooms/${dataroomId}/groups/${groupId}/invite`
      : linkId
        ? `/api/teams/${teamId}/datarooms/${dataroomId}/links/${linkId}/invite`
        : null;

    if (!endpoint) {
      toast.error("Unable to determine invitation endpoint");
      return;
    }

    setLoading(true);

    try {
      const response = await fetch(endpoint, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          ...(groupId ? { linkId: selectedLinkId } : {}),
          customMessage: customMessage.length > 0 ? customMessage : undefined,
          emails: parsedEmails.length > 0 ? parsedEmails : undefined,
        }),
      });

      if (!response.ok) {
        const payload = await response.json().catch(() => null);
        throw new Error(payload?.error ?? "Failed to send invitations");
      }

      const payload = await response.json();
      const sentCount = payload?.success?.length ?? 0;
      const failedCount = payload?.failed?.length ?? 0;

      if (sentCount > 0) {
        toast.success(
          `Invitation${sentCount > 1 ? "s" : ""} sent to ${sentCount} recipient${
            sentCount > 1 ? "s" : ""
          }.`,
        );
      }

      if (failedCount > 0) {
        toast.error(
          `Failed to send to ${failedCount} recipient${
            failedCount > 1 ? "s" : ""
          }.`,
        );
      }

      onSuccess?.();
      if (groupId) {
        mutateUninvited();
      }
      handleClose();
    } catch (error: any) {
      toast.error(error?.message ?? "Failed to send invitations");
      setLoading(false);
    }
  };

  return (
    <Dialog open={open} onOpenChange={setOpen}>
      <DialogContent className="max-h-[90vh] overflow-y-auto sm:max-w-xl">
        <DialogHeader className="text-left">
          <DialogTitle>Share invitation</DialogTitle>
        </DialogHeader>

        <div className="space-y-4">
          {groupId ? (
            <div className="space-y-2">
              <span className="text-sm font-medium text-muted-foreground">
                Choose link
              </span>
              <Select
                value={selectedLinkId}
                onValueChange={setSelectedLinkId}
                disabled={loading}
              >
                <SelectTrigger>
                  <SelectValue placeholder="Select a link" />
                </SelectTrigger>
                <SelectContent>
                  {availableLinks.map((link) => (
                    <SelectItem key={link.id} value={link.id}>
                      {link.name}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            </div>
          ) : null}

          <div className="space-y-2">
            <span className="text-sm font-medium text-muted-foreground">
              Custom message
            </span>
            <Textarea
              value={customMessage}
              onChange={(event) => setCustomMessage(event.target.value)}
              rows={4}
              maxLength={500}
              placeholder="Add a short personal message (optional)"
              className="bg-muted"
              disabled={loading}
            />
            <p className="text-xs text-muted-foreground">
              {customMessage.length}/500 characters
            </p>
          </div>

          <div className="space-y-2">
            <span className="text-sm font-medium text-muted-foreground">
              Recipients
            </span>
            <Textarea
              value={recipientInput}
              onChange={(event) => {
                setRecipientInput(event.target.value);
                setHasEditedRecipients(true);
              }}
              placeholder={
                defaultRecipients.length > 0
                  ? defaultRecipients.join("\n")
                  : "Enter email addresses separated by comma or new line (leave empty to use allowed visitors)"
              }
              className="bg-muted"
              rows={4}
              disabled={loading}
            />
            <p className="text-xs text-muted-foreground">
              Leave blank to invite{" "}
              {defaultRecipients.length > 0
                ? `${defaultRecipients.length} uninvited member${
                    defaultRecipients.length !== 1 ? "s" : ""
                  }`
                : "all allowed visitors"}
              .
            </p>
          </div>

          <Separator />

          <div className="space-y-2 rounded-md border bg-muted/40 p-4 text-sm text-muted-foreground">
            <div>
              <p className="font-medium text-foreground">Email preview</p>
              <p className="text-xs text-muted-foreground">
                Sent from Papermark system email
              </p>
            </div>

            <div className="space-y-1">
              <p>
                <span className="font-medium">Subject:</span> {fallbackSubject}
              </p>
              <p>
                <span className="font-medium">From:</span> {senderEmail}
              </p>
              <p>
                <span className="font-medium">To:</span>{" "}
                {hasEditedRecipients && recipientInput.length > 0
                  ? parseRecipientInput(recipientInput).join(", ")
                  : defaultRecipients.join(", ") || "Selected visitors"}
              </p>
            </div>

            <Separator />

            <div className="space-y-2 text-muted-foreground">
              <p>Hey!</p>
              <p>
                You have been invited to view the{" "}
                <span className="font-semibold text-foreground">
                  {dataroomName}
                </span>{" "}
                dataroom on{" "}
                <span className="font-semibold text-foreground">Papermark</span>
                . The invitation was sent by{" "}
                <span className="font-semibold text-foreground">
                  {senderEmail}
                </span>
                .
              </p>
              {customMessage.length > 0 ? (
                <p className="whitespace-pre-wrap text-foreground">
                  {customMessage}
                </p>
              ) : null}
              <p>
                Click the button below to access the dataroom.
                {selectedLink
                  ? ` Link ID: ${selectedLink.slug ?? selectedLink.id}`
                  : ""}
              </p>
            </div>
          </div>
        </div>

        <DialogFooter>
          <div className="flex w-full flex-col gap-2 sm:flex-row sm:justify-end">
            <Button
              variant="outline"
              type="button"
              onClick={handleClose}
              disabled={loading}
            >
              Cancel
            </Button>
            <Button
              onClick={handleSend}
              loading={loading}
              disabled={groupId ? !selectedLinkId || loading : loading}
            >
              {loading ? "Sending invitations..." : "Send invitations"}
            </Button>
          </div>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}
